#include "../include/BaseLib.hpp"
bool isRun = true;

/*信号处理函数*/
void signal_handle(int);
/*管道*/
static int pipfd[2];

int main()
{
	int sockfd, epollfd, ret;
	std::map<int,BaseLib::ClientData> clientMap;
	char* content;
	char buf[BUF_SIZE] = { 0 };
	char sendBuf[BUF_SIZE] = { 0 };
	epoll_event events[MAX_EVENTS];
	epoll_event event;
	printf("now start to create Server\n");
	sockfd = BaseLib::create_and_bind_socket();
	ret = listen(sockfd, 5);
	ERROR_FUNC(ret < 0, "listen");

	/*创建epoll,并加入sock事件*/
	epollfd = epoll_create1(EPOLL_CLOEXEC);
	ERROR_FUNC(epollfd<0,"epoll_create");
	ret = BaseLib::add_epoll(epollfd,sockfd);
	if(ret < 0) return -1;

	/*创建读写管道*/
	ret = socketpair(PF_UNIX,SOCK_STREAM,0,pipfd);
	if(ret < 0)
	{
		perror("socketpair");
		return -1;
	}
	BaseLib::set_noblocking(pipfd[1]);	//写入端
	BaseLib::add_epoll(epollfd,pipfd[0]);	//读取端

	/*设置一直信号，为其添加处理函数*/
    BaseLib::add_sig(SIGHUP,signal_handle);    //Linux用户退出信号
    BaseLib::add_sig(SIGCHLD,signal_handle);   //用于父进程捕获子进程的终止消息
    BaseLib::add_sig(SIGTERM,signal_handle);   //程序结束信号
    BaseLib::add_sig(SIGINT,signal_handle);    //终止用户写入信号

	/*服务器初始化成功*/
	printf("Start Server Success!,Run Event Loop!\n");

	/*检测配置文件，读取客户端初始化状态*/
	ret = access(FILE_NAME,F_OK);
	if(ret == 0)
		ret = BaseLib::get_file_all(FILE_NAME,&content);
	else
		ret = BaseLib::create_file_for_state(FILE_NAME,&content);
	/*主消息循环*/
	while (isRun) {
		int epoll_count = -1;
		epoll_count = epoll_wait(epollfd, events, MAX_EVENTS, -1);
		if(epoll_count < 0 && errno != EINTR)	
        {
            printf("epoll_wait error!\n");
            break;
        }
		for (int i=0;i<epoll_count;++i)
		{
			if (events[i].data.fd == sockfd && events[i].events & EPOLLIN)
			{
				sockaddr_in address;
				socklen_t length;
				int connfd = accept(sockfd, (sockaddr*)&address, &length);
				printf("%d\n", sockfd);
				ERROR_FUNC(connfd < 0, "accept");
				char strip[64] = { 0 };
				char* ip = inet_ntoa(address.sin_addr);
				strcpy(strip, ip);
				printf("client connect,file descript = [%d],ip = [%s],port = [%d]\n", connfd, strip, ntohs(address.sin_port));
				ret = BaseLib::add_epoll(epollfd,connfd);
				if(ret < 0) continue;

				BaseLib::ClientData data = {
					.type = BaseLib::CLIENT_TYPE::NONE,
					.name = NULL,
					.fd = connfd,
				};
				clientMap[connfd] = data;
				memset(sendBuf, 0, BUF_SIZE);
				sprintf(sendBuf, "Please Enter your name");
				ret = send(connfd, sendBuf, strlen(sendBuf), 0);
			}else if(events[i].data.fd == pipfd[0] && events[i].events & EPOLLIN)
			{
				int sig;
				char msg[1024];
				ret = recv(pipfd[0],msg,sizeof(msg),0);
				if(ret < 0) continue;
				else if(ret == 0) continue;
				else
				{
					/*逐字节读取信号值*/
					for(int i=0;i<ret;++i)
					{
						switch (msg[i])
						{
						case SIGHUP:
							continue;
							break;
						case SIGCHLD:
							break;
						case SIGTERM:
							break;	
						case SIGINT:
							isRun = false;
						default:
							break;
						}
					}
				}
				
			}
			else if (events[i].events & EPOLLIN) 
			{
				int connfd = -1;
				connfd = events[i].data.fd;
				if (connfd < 0) continue;
				auto& data = clientMap.find(connfd)->second;
				switch (data.type)
				{
				case BaseLib::CLIENT_TYPE::NONE:
					ret = read(connfd, buf, BUF_SIZE);
					ERROR_FUNC(ret < 0, "read");
					if (ret == 0) {	
						printf("client close remove:%d\n", connfd);
						close(connfd);
						epoll_ctl(epollfd, EPOLL_CTL_DEL, connfd, &event);
						clientMap.erase(connfd);
					}else{
						ret = BaseLib::ask_server_for_state(content, connfd,buf,data);
						if (ret < 0){
							printf("There is no data for [%d] client ,so we create a new one!\n", connfd);
							data.type = BaseLib::CLIENT_TYPE::REGISTER;
							memset(sendBuf, 0, BUF_SIZE);
							sprintf(sendBuf, "maybe you should register");
							ret = send(connfd, sendBuf, strlen(sendBuf), 0);
						}else{
							memset(sendBuf, 0, BUF_SIZE);
							sprintf(sendBuf, "welcome dear [%s] have a good day",data.name);
							ret = send(connfd, sendBuf, strlen(sendBuf), 0);
						}
					}
					break;
				case BaseLib::CLIENT_TYPE::REGISTER:
					ret = read(connfd, buf, BUF_SIZE);
					ERROR_FUNC(ret < 0, "read");
					if (ret == 0) {	
						printf("client close remove:%d\n", connfd);
						close(connfd);
						epoll_ctl(epollfd, EPOLL_CTL_DEL, connfd, &event);
						clientMap.erase(connfd);
					}
					else
					{
						data.name = (char*)malloc(strlen(buf));
						memcpy(data.name, buf, strlen(buf));
						data.name[strlen(data.name) - 1] = 0;
						memset(sendBuf, 0, BUF_SIZE);
						sprintf(sendBuf, "good we will use [%s] as your name!", data.name);
						ret = send(connfd, sendBuf, strlen(sendBuf),0);
						ERROR_FUNC(ret < 0, "send");
						data.type = BaseLib::CLIENT_TYPE::CHAT;
						BaseLib::save_data_as_json(&content, data);
						BaseLib::save_data_in_file(FILE_NAME, content);
					}
					break;
				case BaseLib::CLIENT_TYPE::CHAT:
					ret = read(connfd, buf, BUF_SIZE);
					ERROR_FUNC(ret < 0, "read");
					if (ret == 0) {
						printf("client close remove:%d\n", connfd);
						close(connfd);
						epoll_ctl(epollfd, EPOLL_CTL_DEL, connfd, &event);
						clientMap.erase(connfd);
					}
					else
					{
						broadcase_message(connfd, clientMap, buf, strlen(buf));
					}
					memset(buf, 0, BUF_SIZE);
					break;
				default:
					break;
				}
			}
		}
	}
	printf("Server Close!\n");
	close(sockfd);
	free(content);
	return 0;
}

void signal_handle(int sig)
{
	int save_error = errno;
	int msg = sig;
	int ret = send(pipfd[1],(char*)&msg,1,0);	//发送一个字节的信号
	errno = save_error;
	return;
}